package net.gdface.reflection.generics;

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeResolver;

import net.gdface.utils.ReflectionUtils.RejectTypeVariable;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 基于{@link TypeResolver}实现的类型变量({@link TypeVariable})解析工具<br>
 * @author guyadong
 * @since 2.10.2
 */
public class EnhancedTypeResolver {

	private final TypeResolver typeResolver;
	private final Map<TypeVariable<?>, Type> typeVariables;
	/**
	 * 构造方法
	 * @param typeVariables 类型变量对应实际类型的映射,
	 * 											参见 {@link net.gdface.utils.ReflectionUtils#getNormalizedTypeVariables(Class, boolean)}
	 */
	public EnhancedTypeResolver(Map<TypeVariable<?>, Type> typeVariables) {
		this.typeVariables = null == typeVariables
					? ImmutableMap.<TypeVariable<?>, Type>of()
					: ImmutableMap.copyOf(typeVariables);
		typeResolver = createTypeResolver(typeVariables);
	}
	public EnhancedTypeResolver() {
		this(Collections.<TypeVariable<?>, Type>emptyMap());
	}
	/**
	 * 根据提供的类型变量-实际类型映射创建{@link TypeResolver}
	 * @param typeVariables
	 */
	public static TypeResolver createTypeResolver(Map<TypeVariable<?>, Type> typeVariables) {
		TypeResolver _typeResolver = new TypeResolver();
		for(Entry<TypeVariable<?>, Type> entry:
			MoreObjects.firstNonNull(typeVariables, Collections.<TypeVariable<?>, Type>emptyMap()).entrySet()) {
			_typeResolver = _typeResolver.where(entry.getKey(), entry.getValue());
		}
		return _typeResolver;
	}
	/**
	 * 从 TypeVariable的上限定义查找，如果找到返回对应的Value,否则返回自己
	 * @param clazz
	 * @since 3.0.1
	 */
	public Class<?> resolveType(Class<?> clazz) {
		if(clazz instanceof Class) {
			Type value;
			Type resolved;
			for(Entry<TypeVariable<?>, Type> entry:typeVariables.entrySet()) {
				TypeVariable<?> key = entry.getKey();
				for(Type bound:key.getBounds()) {
					if(clazz.equals(bound)) {
						if((value = entry.getValue()) instanceof Class) {
							return (Class<?>) value;
						}else {
							if((resolved = typeResolver.resolveType(value)) instanceof Class) {
								return (Class<?>) resolved;
							}
						}
					}
				}
			}
		}
		return clazz;
	}
	/**
	 * @see #resolveType(Class)
	 * @since 3.0.1
	 */
	public Class<?>[] resolveTypes(Class<?>[] classes) {
		Class<?>[] resolved = checkNotNull(classes,"types is null").clone();
		for(int i=0;i<resolved.length;++i) {
			resolved[i] = resolveType(resolved[i]);
		}
		return resolved;
	}
	/**
	 * 解析类型中的所有类型变量，并返回已解析类型变量的对应类型。<br>
	 * 如果是 Class则从 TypeVariable的上限定义查找，如果找到返回对应的Value,否则返回自己
	 * @param type
	 * @see TypeResolver#resolveType(Type)
	 */
	public Type resolveType(Type type) {
		if(type instanceof Class) {
			return resolveType((Class<?>)type);
		}
		return typeResolver.resolveType(type);
	}
	/**
	 * 解析将数组中的类型中的所有类型变量，并返回已解析类型变量的对应类型数组。
	 * @param types
	 * @see TypeResolver#resolveType(Type)
	 */
	public Type[] resolveTypes(Type[] types) {
		Type[] resolved = checkNotNull(types,"types is null").clone();
		for(int i=0;i<resolved.length;++i) {
			resolved[i] = resolveType(resolved[i]);
		}
		return resolved;
	}
	/**
	 * 检查类型中是否有{@link #typeVariables }中已知的类型变量{@link TypeVariable},如果有返回{@code true}
	 * @param type
	 * @since 2.10.2
	 */
	public boolean hasKnownTypeVariable(Type type) {
		return new RejectTypeVariable(type) {
			@Override
			protected void visitTypeVariable(TypeVariable<?> type) {
				if(typeVariables.containsKey(type)) {
					super.visitTypeVariable(type);
				}
			}
		}.isHasTypeVariable();
	}
}
